#ifndef _DEVICE_H
#define _DEVICE_H

#include <compiler.h>

#ifdef __TOP_HALF__

enum devices {
	DEVICE_UART		= 1,
	DEVICE_NAND		= 2,
};

struct device {
	unsigned int id;
	int index;
	void *priv;
};

#define DEVICE(_id, _index, _priv)										\
	struct device __device_##_id										\
		__always_unused __aligned(4) __section(.__devices) = {			\
			.id    = _id,												\
			.index = _index,											\
			.priv  = _priv,												\
	}

struct device *device_lookup_by_id(unsigned int id, int index);

#else

#define O_RDONLY		(0)
#define O_WRONLY		(1)
#define O_RDWR			(2)
#define O_NONBLOCK		(3)
#define O_SYNC			(4)

#define DEV_MODE_READ      (0x1)
#define DEV_MODE_WRITE     (0x2)
#define DEV_MODE_LLSEEK    (0x4)

struct device {
	const char *name;
	int index;
	unsigned int major;
	unsigned int minor;
	struct driver *driver;
	unsigned int flags;
	unsigned int mode;
	void *priv;
};

struct device_operations {
	int (*open)(struct device *dev);
	int (*close)(struct device *dev);
	int (*read)(struct device *dev, void *buf, unsigned int len);
	int (*write)(struct device *dev, const void *buf, unsigned int len);
    loff_t (*llseek)(struct device *dev, loff_t offset, unsigned int origin);
	int (*ioctl)(struct device *dev, unsigned int cmd, unsigned int arg);
};

struct driver {
	const char *name;
	int min_index, max_index;
	unsigned int major;
	unsigned int min_minor, max_minor;
	struct device_operations *dev_ops;
	void *priv;
	struct list_head drv_list;
};

#define DEVICE_START(_name, _index, _major, _minor)						\
	struct device __device_##_name##_index								\
		__always_unused __aligned(4) __section(.__devices) = {			\
			.name  = _name,												\
			.index = _index,											\
			.major = _major,											\
			.minor = _minor,											

#define DEVICE_END														\
};

struct device *device_lookup_by_name(const unsigned char *name, int index);
struct device *device_lookup(unsigned int major, unsigned int minor);
int device_open(struct device *dev, unsigned int flags);
int device_close(struct device *dev);
int device_read(struct device *dev, void *buf, unsigned int len);
int device_write(struct device *dev, const void *buf, unsigned int len);
loff_t device_llseek(struct device *dev, loff_t offset, unsigned int origin);
int device_ioctl(struct device *dev, unsigned int cmd, unsigned int arg);

#endif 

extern struct device __devices_start[], __devices_end[];

#define for_each_device(p)												\
	for (p = __devices_start; p < __devices_end; p++)		
#endif 

#endif /* _DEVICE_H */

